package com.ruoyi.system.service.impl;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.security.utils.DictUtils;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.domain.SysDictData;
import com.ruoyi.system.api.domain.SysDictType;
import com.ruoyi.system.domain.dto.DictDataImportDTO;
import com.ruoyi.system.domain.dto.DictImportDTO;
import com.ruoyi.system.domain.dto.DictImportResultDTO;
import com.ruoyi.system.domain.dto.DictTypeImportDTO;
import com.ruoyi.system.mapper.SysDictDataMapper;
import com.ruoyi.system.mapper.SysDictTypeMapper;
import com.ruoyi.system.service.ISysDictDataService;
import com.ruoyi.system.service.ISysDictTypeService;

/**
 * 字典 业务层处理
 * 
 * @author ruoyi
 */
@Service
public class SysDictTypeServiceImpl implements ISysDictTypeService {
    @Autowired
    private SysDictTypeMapper dictTypeMapper;

    @Autowired
    private SysDictDataMapper dictDataMapper;

    @Autowired
    private ISysDictDataService dictDataService;

    /**
     * 项目启动时，初始化字典到缓存
     */
    @PostConstruct
    public void init() {
        loadingDictCache();
    }

    /**
     * 根据条件分页查询字典类型
     * 
     * @param dictType 字典类型信息
     * @return 字典类型集合信息
     */
    @Override
    public List<SysDictType> selectDictTypeList(SysDictType dictType) {
        return dictTypeMapper.selectDictTypeList(dictType);
    }

    /**
     * 根据所有字典类型
     * 
     * @return 字典类型集合信息
     */
    @Override
    public List<SysDictType> selectDictTypeAll() {
        return dictTypeMapper.selectDictTypeAll();
    }

    /**
     * 根据字典类型查询字典数据
     * 
     * @param dictType 字典类型
     * @return 字典数据集合信息
     */
    @Override
    public List<SysDictData> selectDictDataByType(String dictType) {
        List<SysDictData> dictDatas = DictUtils.getDictCache(dictType);
        if (StringUtils.isNotEmpty(dictDatas)) {
            return dictDatas;
        }
        dictDatas = dictDataMapper.selectDictDataByType(dictType);
        if (StringUtils.isNotEmpty(dictDatas)) {
            DictUtils.setDictCache(dictType, dictDatas);
            return dictDatas;
        }
        return null;
    }

    /**
     * 根据字典类型ID查询信息
     * 
     * @param dictId 字典类型ID
     * @return 字典类型
     */
    @Override
    public SysDictType selectDictTypeById(Long dictId) {
        return dictTypeMapper.selectDictTypeById(dictId);
    }

    /**
     * 根据字典类型查询信息
     * 
     * @param dictType 字典类型
     * @return 字典类型
     */
    @Override
    public SysDictType selectDictTypeByType(String dictType) {
        return dictTypeMapper.selectDictTypeByType(dictType);
    }

    /**
     * 批量删除字典类型信息
     * 
     * @param dictIds 需要删除的字典ID
     */
    @Override
    public void deleteDictTypeByIds(Long[] dictIds) {
        for (Long dictId : dictIds) {
            SysDictType dictType = selectDictTypeById(dictId);
            if (dictDataMapper.countDictDataByType(dictType.getDictType()) > 0) {
                throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName()));
            }
            dictTypeMapper.deleteDictTypeById(dictId);
            DictUtils.removeDictCache(dictType.getDictType());
        }
    }

    /**
     * 加载字典缓存数据
     */
    @Override
    public void loadingDictCache() {
        SysDictData dictData = new SysDictData();
        dictData.setStatus("0");
        Map<String, List<SysDictData>> dictDataMap = dictDataMapper.selectDictDataList(dictData).stream()
                .collect(Collectors.groupingBy(SysDictData::getDictType));
        for (Map.Entry<String, List<SysDictData>> entry : dictDataMap.entrySet()) {
            DictUtils.setDictCache(entry.getKey(), entry.getValue().stream()
                    .sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList()));
        }
    }

    /**
     * 清空字典缓存数据
     */
    @Override
    public void clearDictCache() {
        DictUtils.clearDictCache();
    }

    /**
     * 重置字典缓存数据
     */
    @Override
    public void resetDictCache() {
        clearDictCache();
        loadingDictCache();
    }

    /**
     * 新增保存字典类型信息
     * 
     * @param dict 字典类型信息
     * @return 结果
     */
    @Override
    public int insertDictType(SysDictType dict) {
        int row = dictTypeMapper.insertDictType(dict);
        if (row > 0) {
            DictUtils.setDictCache(dict.getDictType(), null);
        }
        return row;
    }

    /**
     * 修改保存字典类型信息
     * 
     * @param dict 字典类型信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateDictType(SysDictType dict) {
        SysDictType oldDict = dictTypeMapper.selectDictTypeById(dict.getDictId());
        dictDataMapper.updateDictDataType(oldDict.getDictType(), dict.getDictType());
        int row = dictTypeMapper.updateDictType(dict);
        if (row > 0) {
            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(dict.getDictType());
            DictUtils.setDictCache(dict.getDictType(), dictDatas);
        }
        return row;
    }

    /**
     * 校验字典类型称是否唯一
     * 
     * @param dict 字典类型
     * @return 结果
     */
    @Override
    public boolean checkDictTypeUnique(SysDictType dict) {
        Long dictId = StringUtils.isNull(dict.getDictId()) ? -1L : dict.getDictId();
        SysDictType dictType = dictTypeMapper.checkDictTypeUnique(dict.getDictType());
        if (StringUtils.isNotNull(dictType) && dictType.getDictId().longValue() != dictId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 批量导入字典数据
     *
     * @param file XML文件
     * @return 导入结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public DictImportResultDTO batchImportDict(MultipartFile file) {
        DictImportResultDTO result = new DictImportResultDTO();

        try {
            // 解析XML文件
            DictImportDTO importData = parseXmlFile(file);

            // 校验数据
            if (!validateImportData(importData, result)) {
                result.setSuccess(false);
                return result;
            }

            // 执行导入
            importDictData(importData, result);

            // 刷新缓存
            resetDictCache();

            result.setSuccess(result.getErrorMessages().isEmpty());

        } catch (Exception e) {
            result.setSuccess(false);
            result.addErrorMessage("导入失败：" + e.getMessage());
        }

        return result;
    }

    /**
     * 解析XML内容
     *
     * @param xmlContent XML内容
     * @return 解析结果
     */
    @Override
    public DictImportDTO parseXmlContent(String xmlContent) {
        try {
            return parseXmlString(xmlContent);
        } catch (Exception e) {
            throw new ServiceException("XML解析失败：" + e.getMessage());
        }
    }

    /**
     * 批量导入字典数据（从DTO）
     *
     * @param importData 导入数据
     * @return 导入结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public DictImportResultDTO batchImportDictData(DictImportDTO importData) {
        DictImportResultDTO result = new DictImportResultDTO();

        try {
            // 校验数据
            if (!validateImportData(importData, result)) {
                result.setSuccess(false);
                return result;
            }

            // 执行导入
            importDictData(importData, result);

            // 刷新缓存
            resetDictCache();

            result.setSuccess(result.getErrorMessages().isEmpty());

        } catch (Exception e) {
            result.setSuccess(false);
            result.addErrorMessage("导入失败：" + e.getMessage());
        }

        return result;
    }

    /**
     * 解析XML文件
     *
     * @param file XML文件
     * @return 解析结果
     * @throws Exception 解析异常
     */
    private DictImportDTO parseXmlFile(MultipartFile file) throws Exception {
        DictImportDTO importData = new DictImportDTO();
        List<DictTypeImportDTO> dictTypes = new ArrayList<>();

        try (InputStream inputStream = file.getInputStream()) {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(inputStream);

            Element root = document.getDocumentElement();
            if (!"dictionaries".equals(root.getNodeName())) {
                throw new ServiceException("XML根节点必须是dictionaries");
            }

            NodeList dictTypeNodes = root.getElementsByTagName("dictType");
            for (int i = 0; i < dictTypeNodes.getLength(); i++) {
                Node dictTypeNode = dictTypeNodes.item(i);
                if (dictTypeNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element dictTypeElement = (Element) dictTypeNode;
                    DictTypeImportDTO dictType = parseDictType(dictTypeElement);
                    dictTypes.add(dictType);
                }
            }
        }

        importData.setDictTypes(dictTypes);
        return importData;
    }

    /**
     * 解析字典类型节点
     *
     * @param dictTypeElement 字典类型元素
     * @return 字典类型DTO
     */
    private DictTypeImportDTO parseDictType(Element dictTypeElement) {
        DictTypeImportDTO dictType = new DictTypeImportDTO();

        // 解析字典类型基本信息
        dictType.setDictName(getElementText(dictTypeElement, "dictName"));
        dictType.setDictType(getElementText(dictTypeElement, "dictType"));
        dictType.setStatus(getElementText(dictTypeElement, "status", "0"));
        dictType.setRemark(getElementText(dictTypeElement, "remark"));

        // 解析字典数据
        List<DictDataImportDTO> dictDataList = new ArrayList<>();
        NodeList dictDataNodes = dictTypeElement.getElementsByTagName("dictData");
        if (dictDataNodes.getLength() > 0) {
            Element dictDataElement = (Element) dictDataNodes.item(0);
            NodeList itemNodes = dictDataElement.getElementsByTagName("item");

            for (int i = 0; i < itemNodes.getLength(); i++) {
                Node itemNode = itemNodes.item(i);
                if (itemNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element itemElement = (Element) itemNode;
                    DictDataImportDTO dictData = parseDictData(itemElement);
                    dictDataList.add(dictData);
                }
            }
        }

        dictType.setDictData(dictDataList);
        return dictType;
    }

    /**
     * 解析字典数据节点
     *
     * @param itemElement 字典数据元素
     * @return 字典数据DTO
     */
    private DictDataImportDTO parseDictData(Element itemElement) {
        DictDataImportDTO dictData = new DictDataImportDTO();

        String dictSortStr = getElementText(itemElement, "dictSort");
        if (StringUtils.isNotEmpty(dictSortStr)) {
            try {
                dictData.setDictSort(Long.parseLong(dictSortStr));
            } catch (NumberFormatException e) {
                dictData.setDictSort(0L);
            }
        }

        dictData.setDictLabel(getElementText(itemElement, "dictLabel"));
        dictData.setDictValue(getElementText(itemElement, "dictValue"));
        dictData.setCssClass(getElementText(itemElement, "cssClass"));
        dictData.setListClass(getElementText(itemElement, "listClass"));
        dictData.setIsDefault(getElementText(itemElement, "isDefault", "N"));
        dictData.setStatus(getElementText(itemElement, "status", "0"));
        dictData.setRemark(getElementText(itemElement, "remark"));

        return dictData;
    }

    /**
     * 获取元素文本内容
     *
     * @param parent  父元素
     * @param tagName 标签名
     * @return 文本内容
     */
    private String getElementText(Element parent, String tagName) {
        return getElementText(parent, tagName, null);
    }

    /**
     * 获取元素文本内容
     *
     * @param parent       父元素
     * @param tagName      标签名
     * @param defaultValue 默认值
     * @return 文本内容
     */
    private String getElementText(Element parent, String tagName, String defaultValue) {
        NodeList nodeList = parent.getElementsByTagName(tagName);
        if (nodeList.getLength() > 0) {
            Node node = nodeList.item(0);
            if (node != null && node.getFirstChild() != null) {
                return node.getFirstChild().getNodeValue();
            }
        }
        return defaultValue;
    }

    /**
     * 校验导入数据
     *
     * @param importData 导入数据
     * @param result     结果对象
     * @return 校验是否通过
     */
    private boolean validateImportData(DictImportDTO importData, DictImportResultDTO result) {
        if (importData == null || importData.getDictTypes() == null || importData.getDictTypes().isEmpty()) {
            result.addErrorMessage("导入数据为空");
            return false;
        }

        boolean isValid = true;
        Set<String> dictTypeSet = new HashSet<>();

        for (int i = 0; i < importData.getDictTypes().size(); i++) {
            DictTypeImportDTO dictType = importData.getDictTypes().get(i);
            String prefix = "第" + (i + 1) + "个字典类型：";

            // 校验字典类型基本信息
            if (StringUtils.isEmpty(dictType.getDictName())) {
                result.addErrorMessage(prefix + "字典名称不能为空");
                isValid = false;
            } else if (dictType.getDictName().length() > 100) {
                result.addErrorMessage(prefix + "字典名称长度不能超过100个字符");
                isValid = false;
            }

            if (StringUtils.isEmpty(dictType.getDictType())) {
                result.addErrorMessage(prefix + "字典类型不能为空");
                isValid = false;
            } else if (dictType.getDictType().length() > 100) {
                result.addErrorMessage(prefix + "字典类型长度不能超过100个字符");
                isValid = false;
            } else if (dictTypeSet.contains(dictType.getDictType())) {
                result.addErrorMessage(prefix + "字典类型[" + dictType.getDictType() + "]在导入数据中重复");
                isValid = false;
            } else {
                dictTypeSet.add(dictType.getDictType());

                // 检查数据库中是否已存在
                SysDictType existingType = selectDictTypeByType(dictType.getDictType());
                if (existingType != null) {
                    result.addErrorMessage(prefix + "字典类型[" + dictType.getDictType() + "]已存在");
                    isValid = false;
                }
            }

            // 校验状态值
            if (StringUtils.isNotEmpty(dictType.getStatus()) &&
                    !"0".equals(dictType.getStatus()) && !"1".equals(dictType.getStatus())) {
                result.addErrorMessage(prefix + "状态值只能是0或1");
                isValid = false;
            }

            // 校验备注长度
            if (StringUtils.isNotEmpty(dictType.getRemark()) && dictType.getRemark().length() > 500) {
                result.addErrorMessage(prefix + "备注长度不能超过500个字符");
                isValid = false;
            }

            // 校验字典数据
            if (!validateDictData(dictType, result, prefix)) {
                isValid = false;
            }
        }

        return isValid;
    }

    /**
     * 校验字典数据
     *
     * @param dictType 字典类型
     * @param result   结果对象
     * @param prefix   错误信息前缀
     * @return 校验是否通过
     */
    private boolean validateDictData(DictTypeImportDTO dictType, DictImportResultDTO result, String prefix) {
        if (dictType.getDictData() == null || dictType.getDictData().isEmpty()) {
            result.addErrorMessage(prefix + "字典数据不能为空");
            return false;
        }

        boolean isValid = true;
        Set<String> dictValueSet = new HashSet<>();

        for (int i = 0; i < dictType.getDictData().size(); i++) {
            DictDataImportDTO dictData = dictType.getDictData().get(i);
            String dataPrefix = prefix + "第" + (i + 1) + "个字典数据：";

            // 校验必填字段
            if (StringUtils.isEmpty(dictData.getDictLabel())) {
                result.addErrorMessage(dataPrefix + "字典标签不能为空");
                isValid = false;
            } else if (dictData.getDictLabel().length() > 100) {
                result.addErrorMessage(dataPrefix + "字典标签长度不能超过100个字符");
                isValid = false;
            }

            if (StringUtils.isEmpty(dictData.getDictValue())) {
                result.addErrorMessage(dataPrefix + "字典键值不能为空");
                isValid = false;
            } else if (dictData.getDictValue().length() > 100) {
                result.addErrorMessage(dataPrefix + "字典键值长度不能超过100个字符");
                isValid = false;
            } else if (dictValueSet.contains(dictData.getDictValue())) {
                result.addErrorMessage(dataPrefix + "字典键值[" + dictData.getDictValue() + "]在同一字典类型中重复");
                isValid = false;
            } else {
                dictValueSet.add(dictData.getDictValue());
            }

            // 校验排序号
            if (dictData.getDictSort() == null || dictData.getDictSort() < 0) {
                result.addErrorMessage(dataPrefix + "字典排序必须是非负整数");
                isValid = false;
            }

            // 校验枚举值
            if (StringUtils.isNotEmpty(dictData.getIsDefault()) &&
                    !"Y".equals(dictData.getIsDefault()) && !"N".equals(dictData.getIsDefault())) {
                result.addErrorMessage(dataPrefix + "是否默认值只能是Y或N");
                isValid = false;
            }

            if (StringUtils.isNotEmpty(dictData.getStatus()) &&
                    !"0".equals(dictData.getStatus()) && !"1".equals(dictData.getStatus())) {
                result.addErrorMessage(dataPrefix + "状态值只能是0或1");
                isValid = false;
            }

            // 校验长度
            if (StringUtils.isNotEmpty(dictData.getCssClass()) && dictData.getCssClass().length() > 100) {
                result.addErrorMessage(dataPrefix + "CSS样式类长度不能超过100个字符");
                isValid = false;
            }

            if (StringUtils.isNotEmpty(dictData.getListClass()) && dictData.getListClass().length() > 100) {
                result.addErrorMessage(dataPrefix + "列表样式长度不能超过100个字符");
                isValid = false;
            }

            if (StringUtils.isNotEmpty(dictData.getRemark()) && dictData.getRemark().length() > 500) {
                result.addErrorMessage(dataPrefix + "备注长度不能超过500个字符");
                isValid = false;
            }
        }

        return isValid;
    }

    /**
     * 执行导入数据
     *
     * @param importData 导入数据
     * @param result     结果对象
     */
    private void importDictData(DictImportDTO importData, DictImportResultDTO result) {
        String currentUser = SecurityUtils.getUsername();

        for (DictTypeImportDTO dictTypeDto : importData.getDictTypes()) {
            try {
                // 创建字典类型
                SysDictType dictType = new SysDictType();
                dictType.setDictName(dictTypeDto.getDictName());
                dictType.setDictType(dictTypeDto.getDictType());
                dictType.setStatus(StringUtils.isNotEmpty(dictTypeDto.getStatus()) ? dictTypeDto.getStatus() : "0");
                dictType.setRemark(dictTypeDto.getRemark());
                dictType.setCreateBy(currentUser);

                int typeResult = insertDictType(dictType);
                if (typeResult > 0) {
                    result.setSuccessTypeCount(result.getSuccessTypeCount() + 1);
                    result.addSuccessMessage("成功导入字典类型：" + dictType.getDictName());

                    // 创建字典数据
                    for (DictDataImportDTO dictDataDto : dictTypeDto.getDictData()) {
                        try {
                            SysDictData dictData = new SysDictData();
                            dictData.setDictType(dictType.getDictType());
                            dictData.setDictSort(dictDataDto.getDictSort());
                            dictData.setDictLabel(dictDataDto.getDictLabel());
                            dictData.setDictValue(dictDataDto.getDictValue());
                            dictData.setCssClass(dictDataDto.getCssClass());
                            dictData.setListClass(dictDataDto.getListClass());
                            dictData.setIsDefault(
                                    StringUtils.isNotEmpty(dictDataDto.getIsDefault()) ? dictDataDto.getIsDefault()
                                            : "N");
                            dictData.setStatus(
                                    StringUtils.isNotEmpty(dictDataDto.getStatus()) ? dictDataDto.getStatus() : "0");
                            dictData.setRemark(dictDataDto.getRemark());
                            dictData.setCreateBy(currentUser);

                            int dataResult = dictDataService.insertDictData(dictData);
                            if (dataResult > 0) {
                                result.setSuccessDataCount(result.getSuccessDataCount() + 1);
                            } else {
                                result.setFailDataCount(result.getFailDataCount() + 1);
                                result.addErrorMessage("字典数据[" + dictData.getDictLabel() + "]导入失败");
                            }
                        } catch (Exception e) {
                            result.setFailDataCount(result.getFailDataCount() + 1);
                            result.addErrorMessage("字典数据[" + dictDataDto.getDictLabel() + "]导入失败：" + e.getMessage());
                        }
                    }
                } else {
                    result.setFailTypeCount(result.getFailTypeCount() + 1);
                    result.addErrorMessage("字典类型[" + dictType.getDictName() + "]导入失败");
                }
            } catch (Exception e) {
                result.setFailTypeCount(result.getFailTypeCount() + 1);
                result.addErrorMessage("字典类型[" + dictTypeDto.getDictName() + "]导入失败：" + e.getMessage());
            }
        }
    }

    /**
     * 解析XML字符串
     *
     * @param xmlContent XML内容
     * @return 解析结果
     * @throws Exception 解析异常
     */
    private DictImportDTO parseXmlString(String xmlContent) throws Exception {
        DictImportDTO importData = new DictImportDTO();
        List<DictTypeImportDTO> dictTypes = new ArrayList<>();

        try (InputStream inputStream = new java.io.ByteArrayInputStream(xmlContent.getBytes("UTF-8"))) {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(inputStream);

            Element root = document.getDocumentElement();
            if (!"dictionaries".equals(root.getNodeName())) {
                throw new ServiceException("XML根节点必须是dictionaries");
            }

            // 只获取根节点的直接子节点dictType，避免获取嵌套的dictType元素
            NodeList childNodes = root.getChildNodes();
            for (int i = 0; i < childNodes.getLength(); i++) {
                Node childNode = childNodes.item(i);
                if (childNode.getNodeType() == Node.ELEMENT_NODE && "dictType".equals(childNode.getNodeName())) {
                    Element dictTypeElement = (Element) childNode;
                    DictTypeImportDTO dictType = parseDictType(dictTypeElement);
                    dictTypes.add(dictType);
                }
            }
        }

        importData.setDictTypes(dictTypes);
        return importData;
    }
}
